/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.cratos.xxgram.platf.push;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.annotation.Resource;

import org.redkale.boot.Application;
import org.redkale.convert.json.JsonConvert;
import org.redkale.service.RetResult;
import org.redkale.source.FilterExpress;
import org.redkale.source.FilterNode;
import org.redkale.util.AnyValue;
import org.redkale.util.Comment;
import org.redkale.util.Utility;

import com.cratos.xxgram.platf.base.BaseService;
import com.cratos.xxgram.platf.base.RetCodes;
import com.cratos.xxgram.platf.message.MessageRecord;
import com.cratos.xxgram.platf.message.NotifyContent;
import com.cratos.xxgram.platf.user.UserDetail;
import com.cratos.xxgram.platf.util.QueueTask;

/**
 *
 * @href =https://docs.jiguang.cn/jpush/console/Instructions/
 * @author SquRab
 */
@Comment("极光推送")
public class JpushService extends BaseService {

    @Resource(name = "property.jpush.host")
    private String host = "https://bjapi.push.jiguang.cn";

    @Resource(name = "property.jpush.appKey")
    private String appKey = "";

    @Resource(name = "property.jpush.appSecret")
    private String appSecret = "";

    private Map<String, String> header = new HashMap();

    private final String REQ_AUTH_KEY = "Authorization";

    private final String REQ_AUTH_VAL_PREFIX = "Basic ";

    @Resource
    static JsonConvert convert = JsonConvert.root();

    @Resource(name = "property.jpush.production")
    protected boolean production = true; //默认是给测试环境
    
    @Comment("融云")
    protected final QueueTask<Message> messageQueue = new QueueTask<>(1);
    
    public final Map<Integer, String> pushMsgType = new HashMap<Integer, String>();
    
    private void initPushMsgType() {
    	
    	pushMsgType.put(1001, "文本消息");
    	pushMsgType.put(1002, "语音");
    	pushMsgType.put(1003, "文件类的消息");
		pushMsgType.put(1004, "小视频消息");
		
		
		pushMsgType.put(1005, "位置消息");
		pushMsgType.put(1006, "图文消息");
		pushMsgType.put(1007, "群聊自定义消息");
		pushMsgType.put(1008, "文件类分享转发");
		
		
		pushMsgType.put(1009, "音频消息");
		pushMsgType.put(1010, "图片消息");
		pushMsgType.put(1012, "分享名片");
		pushMsgType.put(1013, "融云语音通话消息");
		pushMsgType.put(1014, "系统公告");
		pushMsgType.put(1015, "消息合并转发");
                
		pushMsgType.put((int) NotifyContent.OBJ_CONTRACT_NTF, "联系人(好友)通知消息 用来发送联系人操作（加好友等）的通知消息");
		pushMsgType.put((int) NotifyContent.OBJ_CONTRACT_LOCAL_NTF, "联系人(好友)通知消息 用来发送联系人操作（加好友等）的通知消息");
		pushMsgType.put((int) NotifyContent.OBJ_CREATE_GROUP_NTF, "新建群");
		
		pushMsgType.put((int) NotifyContent.OBJ_UPDATE_GROUP_NTF, "更新群");
		pushMsgType.put((int) NotifyContent.OBJ_ADD_MEMBER_GROUP_NTF, "添加群成员");
		pushMsgType.put((int) NotifyContent.OBJ_KICK_GROUP_NTF, "踢出群成员");
		pushMsgType.put((int) NotifyContent.OBJ_QUIT_GROUP_NTF, "退出群");
		pushMsgType.put((int) NotifyContent.OBJ_DISMISS_GROUP_NTF, "解散群");
		
		pushMsgType.put((int) NotifyContent.OBJ_FORBIDDENWORD_NTF, "群禁言");
		
		pushMsgType.put((int) NotifyContent.OBJ_GROUP_UPDATE_TYPE_NTF, "更新群类型");
                
		
    }
    @Override
    public void init(AnyValue config) {
        header.put(REQ_AUTH_KEY, REQ_AUTH_VAL_PREFIX + Base64.getEncoder().encodeToString((appKey + ":" + appSecret).getBytes()));
        Consumer<Message> cloudMessage = (Message message) -> {
             RetResult result = null;
           try{
        	   logger.finest("before send message ... ===" + convert.convertTo(message));
                result = pushMessage(message);
               logger.finest("push result ===" + convert.convertTo(result));
           } catch(Exception e) {
               logger.finest("push Exception res  ===" + convert.convertTo(result) + ", error " + e.getMessage());
               e.printStackTrace();
           }
        };
        initPushMsgType();
        messageQueue.init(logger, cloudMessage);
        super.init(config);
    }

    public static void main(String[] args) throws IOException, Exception {
        JpushService service = Application.singleton(JpushService.class);
        List<Integer> ids = new ArrayList<>();
        ids.add(300000001);
        ids.add(300000002);
        Integer[] idarray = new Integer[ids.size()];
        int index = 0;
        for (Integer id : ids) {
        	idarray[index++]= id;
        }
        Object o = service.source.queryColumnList("jpregid", UserDetail.class, FilterNode.create("userid", FilterExpress.IN, idarray));
        System.out.println(o);
        //\"alias\":[301033041],
        
        String msg = "{\"audience\":{\"registration_id\":[\"100d855909d85ee89a6\"]},\"message\":{\"msg_content\":\"{\\\"clienttype\\\":\\\"WEB\\\",\\\"content\\\":\\\"{\\\\\\\"content\\\\\\\":\\\\\\\"22\\\\\\\"}\\\",\\\"createtime\\\":1586237581235,\\\"encrypt\\\":10,\\\"fromid\\\":304491669,\\\"messageid\\\":\\\"304491669-104619836-k8pgweux\\\",\\\"msgkind\\\":30,\\\"msgtype\\\":1001,\\\"status\\\":10,\\\"targetid\\\":104619836}\",\"title\":\"Xxgram\"},\"notification\":{\"android\":{\"alert\":\"您有一条新消息\",\"title\":\"Xxgram\"},\"ios\":{\"alert\":\"您有一条新消息!\",\"sound\":\"default\"}},\"options\":{\"apns_production\":true,\"time_to_live\":50},\"platform\":\"all\"}";
        String oldMsg = "{\\\"audience\\\":{\\\"registration_id\\\":[\\\"101d855909df3bf93b4\\\",\\\"101d855909d6409b737\\\"]},\\\"message\\\":{\\\"msg_content\\\":\\\"{\\\\\\\"clienttype\\\\\\\":\\\\\\\"Android\\\\\\\",\\\\\\\"content\\\\\\\":\\\\\\\"{\\\\\\\\\\\\\\\"mentionedInfo\\\\\\\\\\\\\\\":{\\\\\\\\\\\\\\\"type\\\\\\\\\\\\\\\":0},\\\\\\\\\\\\\\\"content\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"22\\\\\\\\\\\\\\\"}\\\\\\\",\\\\\\\"createtime\\\\\\\":1585384251958,\\\\\\\"encrypt\\\\\\\":10,\\\\\\\"fromid\\\\\\\":300000014,\\\\\\\"messageid\\\\\\\":\\\\\\\"300000014-300000003-k8bcum6b\\\\\\\",\\\\\\\"msgkind\\\\\\\":20,\\\\\\\"msgtype\\\\\\\":1001,\\\\\\\"status\\\\\\\":10,\\\\\\\"targetid\\\\\\\":300000003}\\\",\\\"title\\\":\\\"Xxgram\\\"},\\\"notification\\\":{\\\"android\\\":{\\\"alert\\\":\\\"您有一条新消息\\\",\\\"title\\\":\\\"Xxgram\\\"},\\\"ios\\\":{\\\"alert\\\":\\\"您有一条新消息!\\\",\\\"sound\\\":\\\"default\\\"}},\\\"options\\\":{\\\"apns_production\\\":true,\\\"time_to_live\\\":50},\\\"platform\\\":\\\"all\\\"}";
//        RetResult ret  = service.post("https://bjapi.push.jiguang.cn/v3/push", "{\"audience\":{\"registration_id\":[\"101d855909df3bf93b4\",\"101d855909d6409b737\"]},\"message\":{\"msg_content\":\"{\\\"clienttype\\\":\\\"Android\\\",\\\"content\\\":\\\"{\\\\\\\"mentionedInfo\\\\\\\":{\\\\\\\"type\\\\\\\":0},\\\\\\\"content\\\\\\\":\\\\\\\"22\\\\\\\"}\\\",\\\"createtime\\\":1585384251958,\\\"encrypt\\\":10,\\\"fromid\\\":300000014,\\\"messageid\\\":\\\"300000014-300000003-k8bcum6b\\\",\\\"msgkind\\\":20,\\\"msgtype\\\":1001,\\\"status\\\":10,\\\"targetid\\\":300000003}\",\"title\":\"Xxgram\"},\"notification\":{\"android\":{\"alert\":\"您有一条新消息\",\"title\":\"Xxgram\"},\"ios\":{\"alert\":\"您有一条新消息!\",\"sound\":\"default\"}},\"options\":{\"apns_production\":true,\"time_to_live\":50},\"platform\":\"all\"}\n" + 
//        		"");
        
        RetResult ret  = service.post("https://bjapi.push.jiguang.cn/v3/push", msg);
       System.out.println(service.pushMsgType.containsKey(1008));
        System.out.println(ret);
        // 300000015, 101d855909d6409b737
//        Message message = new Message();
//        MessageRecord messageRecord = new MessageRecord();
//        message.setAudience(new Message.Audience(null, Arrays.asList(300000014)));
        
//      Message.MessageData data = new Message.MessageData();
//      message.setMessage(data);
//      data.setMsg_content(messageRecord.toString());
//      data.setTitle("Xxgram");
//      message.setOptions(new Message.Options(false));
//      
//      Message.Notification notification = new Message.Notification();
//      Message.Notification.Android android = new Message.Notification.Android();
//      Message.Notification.IOS ios = new Message.Notification.IOS();
//      
//      ios.alert ="您有一条新消息!";
//      ios.sound = "default";
//      
//      notification.ios = ios;
//      android.alert = "您有一条新消息";
//      android.title = "Xxgram";
//      notification.android = android;
//      message.setNotification(notification);
//      service.messageQueue.add(message);
        Thread.sleep(1000 * 30);
    }
    
    public RetResult pushMessage(MessageRecord messageRecord, Collection<Integer> userids) {
        // 过滤掉 其他不需要提示的消息
        boolean isfilter = pushMsgType.containsKey((int )messageRecord.getMsgtype());
        logger.finest("pushMessage === record :" + convert.convertTo(messageRecord) + ", userids :" + convert.convertTo(userids)+", pushMsgType size ==" + pushMsgType.size()+", isfilter ======" + isfilter);
        if (!isfilter || userids.isEmpty()) {
        	return RetResult.success();
        }
        Message message = new Message();
        List<String> regids = null;
        Integer[] idarray = new Integer[userids.size()];
        int index = 0;
        for (Integer id : userids) {
        	idarray[index++]= id;
        }
        try {
        	regids = source.queryColumnList("jpregid", UserDetail.class, FilterNode.create("userid", FilterExpress.IN, idarray));
        }catch (Exception e) {
        	e.printStackTrace();
        	 logger.finest("jpregid error... === :" + e.getMessage());
        }
        logger.finest("regids... === :" +convert.convertTo(regids) +", message ======"+ convert.convertTo(message));
        message.setAudience(new Message.Audience(regids));
//        message.setAudience(new Message.Audience(userids));
        Message.MessageData data = new Message.MessageData();
        message.setMessage(data);
        data.setMsg_content(messageRecord.toString());
        data.setTitle("Xxgram");
        message.setOptions(new Message.Options(production));
        
        Message.Notification notification = new Message.Notification();
        Message.Notification.Android android = new Message.Notification.Android();
        Message.Notification.IOS ios = new Message.Notification.IOS();
        
        ios.alert ="您有一条新消息!";
        ios.sound = "default";
        
        notification.ios = ios;
        android.alert = "您有一条新消息";
        android.title = "Xxgram";
        notification.android = android;
        message.setNotification(notification);
        
        logger.finest("messageInfo === :" + convert.convertTo(message));
        
        messageQueue.add(message);
        return RetResult.success();
    }

    public RetResult<Response> post(String url, String body) {
        String postHttpContent = null;
        Response response = null;
        try {
            logger.finest("req url = " + url + ",req body = " + body);
            postHttpContent = Utility.postHttpContent(url, 10000, header, body);
            response = JsonConvert.root().convertFrom(Response.class, postHttpContent);
            logger.finest("response ===>>>>>> " + postHttpContent);
            if (response.getError() != null) {
                Logger.getLogger(JpushService.class.getName()).log(Level.SEVERE, null, postHttpContent);
                return RetCodes.retResult(RetCodes.RET_JPUSH_FAIL);
            }
        } catch (IOException ex) {
        	ex.printStackTrace();
        	 System.out.println("response error ===>>>>>> " + ex.getMessage());
            Logger.getLogger(JpushService.class.getName()).log(Level.SEVERE, null, ex);
            return RetCodes.retResult(RetCodes.RET_JPUSH_FAIL);
        }
        return RetResult.success(response);
    }

    @Comment("推送消息")
    private RetResult pushMessage(Message message) {
        return post(host + "/v3/push", convert.convertTo(message));
    }

    public static class Response {

        public String getSendno() {
            return sendno;
        }

        public void setSendno(String sendno) {
            this.sendno = sendno;
        }

        public String getMsg_id() {
            return msg_id;
        }

        public void setMsg_id(String msg_id) {
            this.msg_id = msg_id;
        }

        public ErrorData getError() {
            return error;
        }

        public void setError(ErrorData error) {
            this.error = error;
        }

        private String sendno;

        private String msg_id;

        private ErrorData error;

        public static class ErrorData {

            private int code;

            private String message;

            public int getCode() {
                return code;
            }

            public void setCode(int code) {
                this.code = code;
            }

            public String getMessage() {
                return message;
            }

            public void setMessage(String message) {
                this.message = message;
            }

        }
    }

    @Comment("消息推送")
    public static class Message {

        @Comment("接收平台all 表示ios android winphone")
        private String platform = "all";

        @Comment("推送所有平台")
        public static final String PLATFORM_ALL = "all";

        @Comment("推送android平台")
        public static final String PLATFORM_ANDROID = "android";

        @Comment("推送ios平台")
        public static final String PLATFORM_IOS = "ios";

        @Comment("推送winphone平台")
        public static final String PLATFORM_WINPHONE = "winphone";

        @Comment("接收用户regids")
        private Audience audience;

        @Comment("通知")
        private Notification notification;

        @Comment("消息内容")
        private MessageData message;

        @Comment("环境设置")
        private Options options;

        public Options getOptions() {
            return options;
        }

        public void setOptions(Options options) {
            this.options = options;
        }
        
        public Message() {
        }

        public Message(String platform, Audience audience, Notification notification, MessageData message, Options options) {
            this.audience = audience;
            this.notification = notification;
            this.message = message;
            this.platform = platform;
            this.options = options;
        }

        public Notification getNotification() {
            return notification;
        }

        public void setNotification(Notification notification) {
            this.notification = notification;
        }

        public MessageData getMessage() {
            return message;
        }

        public void setMessage(MessageData message) {
            this.message = message;
        }

        public String getPlatform() {
            return platform;
        }

        public void setPlatform(String platform) {
            this.platform = platform;
        }

        public Audience getAudience() {
            return audience;
        }

        public void setAudience(Audience audience) {
            this.audience = audience;
        }

        public static class Audience {

            private Collection<String> registration_id;

//            private Collection<Integer> alias;

            public Collection<String> getRegistration_id() {
                return registration_id;
            }

            public void setRegistration_id(Collection<String> registration_id) {
                this.registration_id = registration_id;
            }

            public Audience(Collection<String> registration_id) {
                this.registration_id = registration_id;
            }

            
            
        }
        
        public static class Options {
            
            private int time_to_live = 50;
            
            @Comment("生产环境设置")
            private Object apns_production = true;
            
            private String apns_collapse_id;

            public int getTime_to_live() {
                return time_to_live;
            }

            public void setTime_to_live(int time_to_live) {
                this.time_to_live = time_to_live;
            }

            public Object getApns_production() {
                return apns_production;
            }

            public void setApns_production(boolean apns_production) {
                this.apns_production = apns_production;
            }

            public String getApns_collapse_id() {
                return apns_collapse_id;
            }

            public void setApns_collapse_id(String apns_collapse_id) {
                this.apns_collapse_id = apns_collapse_id;
            }

            public Options(boolean apns_production) {
               this.apns_production = apns_production;
            }
            
            public Options() {
            }
            
        }
        @Comment("通知 参考 https://docs.jiguang.cn//jpush/server/push/rest_api_v3_push/#_6")
        public static class Notification {

            @Comment("android 平台通知格式")
            private Android android;

            @Comment("ios 平台通知格式")
            private IOS ios;

            public IOS getIos() {
                return ios;
            }

            public void setIos(IOS ios) {
                this.ios = ios;
            }

            public Android getAndroid() {
                return android;
            }

            public void setAndroid(Android android) {
                this.android = android;
            }

            public static class Android {

                @Comment("提示信息")
                private String alert;

                @Comment("标题")
                private String title;

                @Comment("通知栏样式 ID	 Android SDK 可设置通知栏样式，这里根据样式 ID 来指定该使用哪套样式，android 8.0 开始建议采用NotificationChannel配置。")
                private Integer builder_id;

                @Comment("图标路径可以是以http或https开头的网络图片，如：http:jiguang.cn/logo.png ,图标大小不超过 30 k; 也可以是位于drawable资源文件夹的图标路径，如：R.drawable.lg_icon；")
                private String large_icon;

                @Comment("指定跳转页面 使用 intent 里的 url 指定点击通知栏后跳转的目标页面;")
                private Map<String, String> intent;

                @Comment("附加字段")
                private Map<String, Object> extras;

                public Android() {

                }

                public String getAlert() {
                    return alert;
                }

                public void setAlert(String alert) {
                    this.alert = alert;
                }

                public String getTitle() {
                    return title;
                }

                public void setTitle(String title) {
                    this.title = title;
                }

                public Android(String alert, String title) {
                    this.alert = alert;
                    this.title = title;
                }

                public Integer getBuilder_id() {
                    return builder_id;
                }

                public void setBuilder_id(Integer builder_id) {
                    this.builder_id = builder_id;
                }

                public String getLarge_icon() {
                    return large_icon;
                }

                public void setLarge_icon(String large_icon) {
                    this.large_icon = large_icon;
                }

                public Map<String, String> getIntent() {
                    return intent;
                }

                public void setIntent(Map<String, String> intent) {
                    this.intent = intent;
                }

                public Map<String, Object> getExtras() {
                    return extras;
                }

                public void setExtras(Map<String, Object> extras) {
                    this.extras = extras;
                }

            }

            public static class IOS {

                @Comment("通知内容")
                private String alert;

                @Comment("通知提示声音或警告通知	")
                private String sound;

                @Comment("应用角标,如果不填，表示不改变角标数字，否则把角标数字改为指定的数字；为 0 表示清除。JPush 官方 SDK 会默认填充 badge 值为 \"+1\",详情参考：badge +1")
                private String badge;

                @Comment("这里自定义 Key / value 信息，以供业务使用。")
                private Map<String, Object> extras;

                public String getAlert() {
                    return alert;
                }

                public void setAlert(String alert) {
                    this.alert = alert;
                }

                public String getSound() {
                    return sound;
                }

                public void setSound(String sound) {
                    this.sound = sound;
                }

                public String getBadge() {
                    return badge;
                }

                public void setBadge(String badge) {
                    this.badge = badge;
                }

                public Map<String, Object> getExtras() {
                    return extras;
                }

                public void setExtras(Map<String, Object> extras) {
                    this.extras = extras;
                }

            }
        }

        @Comment("通知")
        public static class MessageData {

            @Comment("消息内容")
            private String msg_content;

            private String title;

            public String getTitle() {
                return title;
            }

            public void setTitle(String title) {
                this.title = title;
            }

            public String getMsg_content() {
                return msg_content;
            }

            public void setMsg_content(String msg_content) {
                this.msg_content = msg_content;
            }

        }

//        public static class Builder {
//
//            private String platform = "all";
//
//            @Comment("接收用户regid")
//            private Audience audience;
//
//            @Comment("通知")
//            private Notification notification;
//
//            @Comment("消息内容")
//            private MessageData message;
//
//            private Options options;
//            public Builder platform(String platform) {
//                this.platform = platform;
//                return this;
//            }
//
////            public Builder audience(List<Integer> alias) {
////                this.audience = new Audience(alias);
////                return this;
////            }
//
//            public Builder notification(Notification notification) {
//                this.notification = notification;
//                return this;
//            }
//
//            public Builder message(MessageData message) {
//                this.message = message;
//                return this;
//            }
//
//            
//            public Message build() {
//                return new Message(platform, audience, notification, message, options);
//            }
//        }
    }

}
